Skip to content

Move foundry's compiler settings back under [profile.default] - #38

Merged
thedavidmeister merged 1 commit into
mainfrom
2026-08-18-issue-37-foundry-profile-keys
Aug 18, 2026
Merged

Move foundry's compiler settings back under [profile.default]#38
thedavidmeister merged 1 commit into
mainfrom
2026-08-18-issue-37-foundry-profile-keys

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Closes #37.

TOML assigns every key to the header above it. Since the soldeer migration
(73a6669, 2026-05-09) inserted [dependencies] and [soldeer] between
[profile.default] and the rest of the file, solc, evm_version,
optimizer, optimizer_runs, bytecode_hash and cbor_metadata have been
soldeer config, and forge has used its own defaults for all six.

This moves every foundry header above [dependencies] and [soldeer], so no
foundry key can be captured by a soldeer header. [fuzz] moves with them: it
was already being read (foundry accepts it at the root wherever it sits), but
leaving it below [soldeer] would leave the same shape in the file for the
next key to be appended into.

forge config, before and after

nix develop -c forge config, on main and on this branch:

key main this branch file declares
solc (absent — auto_detect_solc = true) "0.8.25" 0.8.25
evm_version "osaka" "cancun" cancun
optimizer false true true
optimizer_runs 200 1000000 1000000
bytecode_hash "ipfs" "none" none
cbor_metadata true false false
[fuzz] runs 2048 2048 2048

Every key now reports the file's value. Forge emits no unknown-section warning
either way, which is why this was silent.

What actually moves in the bytecode

Both configs built from an empty out/cache with forge build --force on
the same toolchain.

Two of the six settings turn out to have been inert but harmless. The old
build's artifact metadata reads solc 0.8.25+commit.b61c2a91 and
evmVersion: cancunauto_detect_solc resolved to 0.8.25 because the test
pins pragma solidity =0.8.25, and foundry clamps the EVM version down to the
newest one the selected solc supports, which for 0.8.25 is cancun. The osaka
that forge config reported never reached the compiler.

What did move is the optimizer and the metadata — old
optimizer {enabled: false, runs: 200}, bytecodeHash: ipfs; new
{enabled: true, runs: 1000000}, bytecodeHash: none:

artifact runtime, main runtime, here creation, main creation, here
LibCtPop 86 B 32 B 161 B 82 B
LibCtPopTest 8429 B 7294 B 8509 B 7351 B

LibCtPop's deployed artifact is only the non-callable library stub — both
its functions are internal — so most of its 86 bytes were the IPFS metadata
hash that bytecode_hash = "none" was meant to suppress.

Nothing in the repo pins bytecode, and the gas snapshot is already correct

src/ is one internal-only library, there is no script/, and there is no
address, code hash or CREATE2 salt constant anywhere in the tree. Nothing needs
regenerating on that count.

.gas-snapshot does not need regenerating either, because it was written under
the settings this branch restores. forge snapshot here reproduces the
committed numbers exactly for all six tests the file contains:

                          .gas-snapshot   this branch   main
testCtPop0                          741           741    858
testCtPop1                          764           764    888
testCtPop256EdgeCase                677           677    736
testCtPopReference           789 / ~790    789 / ~790   1075 / ~1076
testCtPopUnshuffled                 989           989   1337
testCtPopShuffled               144,902       144,925  302,573

(testCtPopShuffled is a fuzz mean; 144,902 vs 144,925 is input noise, not a
code change.)

It is separately stale in one respect that predates and outlives this PR:
testCtPopLoneHighBit and testMaskConstantsRederived, added in 5846438 on
2026-07-18, were never snapped. Nothing in CI reads the file — rainix-sol-test
runs forge test only — so it has been drifting unchecked. Left alone here
rather than folded into a compiler-settings change.

Consumers of the published package are unaffected

Soldeer publishes source, not artifacts. .soldeerignore excludes /out,
/foundry.toml, /cache, /dependencies and /test, so a published revision
is src/** plus README and LICENSES. LibCtPop's two functions are both
internal, so they are inlined into the consumer's own compilation unit and
compiled entirely under the consumer's settings. No published revision has ever
carried this repo's compiler settings or any bytecode built from them, so there
is nothing for a consumer to re-pull or re-verify. (#37 says every published
revision was compiled unoptimised; that is not what a Soldeer revision
contains. Corrected on the issue.)

What the defect did cost

This repo's own build and CI ran unoptimised, at optimizer_runs = 200, with
an IPFS metadata hash in every artifact — so builds were not byte-reproducible
across machines, which is exactly what bytecode_hash = "none" and
cbor_metadata = false were there to guarantee. The EVM version was right by
accident, and the source is plain arithmetic with no assembly and no
cancun-only opcode, so no test was exercising the wrong instruction set.

Sibling sweep

#37 asks for a sweep. Every foundry.toml on the default branch of all 186
non-archived repos across rainlanguage, cyclofinance, S01-Issuer,
ST0x-Technology and gildlab — 54 files, 48 at a repo root plus 6 nested (rainix's CI fixture,
rain.subgraph.docker's example, and four in the foundry/pyth-crosschain
upstream forks) — checked for a foundry profile key sitting under a
[dependencies], [soldeer] or [external.*] header.

rain.math.binary is the only one. Nothing filed for the others.

QA

  • Discriminating tests: no Solidity test can observe compiler configuration
    from inside the EVM, so the discriminating check is the one foundry.toml compiler settings sit inside [soldeer], so forge ignores every one of them #37 names —
    nix develop -c forge config, run on a47d3e7 (base) and on this branch.
    All six keys report foundry defaults on base and the file's values here; the
    table above is that output. forge test passes 8/8 under the new settings.
  • Mutations applied: the diff is itself the mutation, applied in both
    directions and observed. foundry.toml (base) -> foundry.toml (branch),
    each built from an empty out/cache with forge build --force: artifact
    metadata moves optimizer {enabled: false, runs: 200} -> {enabled: true, runs: 1000000} and bytecodeHash: ipfs -> none; LibCtPop runtime
    86 B -> 32 B, LibCtPopTest runtime 8429 B -> 7294 B; gas moves as tabulated
    (e.g. testCtPopShuffled 302,573 -> 144,925). Reverting the section move
    restores every base value, so the change is load-bearing and nothing else in
    the tree is producing the effect.
  • Oracle: foundry.toml's own declared values, which are independent of what
    forge was doing — the file states 0.8.25, cancun, optimizer = true,
    optimizer_runs = 1000000, bytecode_hash = "none", cbor_metadata = false,
    and forge config must report exactly those. The .gas-snapshot committed in
    January, generated before 73a6669 broke the ordering, is a second independent
    oracle: this branch reproduces its numbers, main does not.
  • Category check: foundry.toml compiler settings sit inside [soldeer], so forge ignores every one of them #37 asks for (a) the keys moved into [profile.default],
    (b) forge config verified for all six named keys, (c) a sibling sweep.
    Covered a, b, c. The sweep is report-only per the issue's "worth sweeping"
    framing; rain.math.binary was the only hit, so nothing was filed.

TOML assigns a key to the header above it. `solc`, `evm_version`, `optimizer`,
`optimizer_runs`, `bytecode_hash` and `cbor_metadata` sat below `[soldeer]`, so
they were soldeer config and forge fell back to its own defaults for all six.

All of foundry's headers now precede `[dependencies]` and `[soldeer]`, so no
foundry key can be captured by a soldeer header. `[fuzz]` moves with them; it
was already being read, since foundry accepts it at the root wherever it sits.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 402d1a04-4ccd-4bac-a83f-7e7469e44d09

📥 Commits

Reviewing files that changed from the base of the PR and between a47d3e7 and 01188e1.

📒 Files selected for processing (1)
  • foundry.toml

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


Walkthrough

Changes

Foundry configuration

Layer / File(s) Summary
Foundry profile and tool sections
foundry.toml
Build settings, including evm_version, optimizer options, and reproducible-bytecode metadata, now remain under [profile.default]. [dependencies] and [soldeer] follow the profile and fuzz configuration as separate sections.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 01188

This is a localized compiler-configuration correction in foundry.toml, with the declared settings restored and validation reported for configuration output and tests. No actionable merge-blocking risk remains beyond normal checks and review.

Suggested reviewers: dcatki

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #37 by placing compiler, optimizer, metadata, EVM, and fuzz settings under [profile.default].
Out of Scope Changes check ✅ Passed The changes are limited to reorganizing and clarifying foundry.toml settings required by issue #37.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: moving Foundry compiler settings under [profile.default].
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-08-18-issue-37-foundry-profile-keys

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thedavidmeister
thedavidmeister merged commit c85efb0 into main Aug 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

foundry.toml compiler settings sit inside [soldeer], so forge ignores every one of them

1 participant